﻿/*!	@file
	@brief 表示用文字列等の取得

	機能名，機能分類，機能番号などの変換．設定画面での表示用文字列を用意する．

	@author genta
	@date Oct.  1, 2001 マクロ
	@date Oct. 15, 2001 カスタムメニュー
*/
/*
	Copyright (C) 2001, genta
	Copyright (C) 2007, ryoji
	Copyright (C) 2018-2022, Sakura Editor Organization

	SPDX-License-Identifier: Zlib
*/

#include "StdAfx.h"
#include "func/CFuncLookup.h"
#include "plugin/CJackManager.h"
#include "apiwrap/StdControl.h"
#include "CSelectLang.h"
#include "String_define.h"

//	オフセット値
const int LUOFFSET_MACRO = 0;
const int LUOFFSET_CUSTMENU = 1;
const int LUOFFSET_PLUGIN = 2;

/*!	@brief 分類中の位置に対応する機能番号を返す．

	@param category [in] 分類番号 (0-)
	@param position [in] 分類中のindex (0-)
	@param bGetUnavailable [in] 未登録マクロでも機能番号を返す

	@retval 機能番号

	@date 2007.11.02 ryoji bGetUnavailableパラメータ追加
*/
EFunctionCode CFuncLookup::Pos2FuncCode( int category, int position, bool bGetUnavailable ) const
{
	if( category < 0 || position < 0 )
		return F_DISABLE;

	if( category < nsFuncCode::nFuncKindNum ){
		if( position < nsFuncCode::pnFuncListNumArr[category] )
			return nsFuncCode::ppnFuncListArr[category][position];
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_MACRO ){
		//	キー割り当てマクロ
		if( position < MAX_CUSTMACRO ){
			if( bGetUnavailable || m_pMacroRec[position].IsEnabled() )
				return (EFunctionCode)(F_USERMACRO_0 + position);
		}
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_CUSTMENU ){
		//	カスタムメニュー
		if( position == 0 )
			return F_MENU_RBUTTON;
		else if( position < MAX_CUSTOM_MENU )
			return (EFunctionCode)(F_CUSTMENU_BASE + position);
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_PLUGIN ){
		//	プラグイン
		return CJackManager::getInstance()->GetCommandCode( position );
	}
	return F_DISABLE;
}

/*!	@brief 分類中の位置に対応する機能名称を返す．

	@retval true 指定された機能番号は定義されている
	@retval false 指定された機能番号は未定義

	@date 2007.11.02 ryoji 処理を簡素化
*/
bool CFuncLookup::Pos2FuncName(
	int		category,	//!< [in]  分類番号 (0-)
	int		position,	//!< [in]  分類中のindex (0-)
	WCHAR*	ptr,		//!< [out] 文字列を格納するバッファの先頭
	int		bufsize		//!< [in]  文字列を格納するバッファのサイズ
) const
{
	int funccode = Pos2FuncCode( category, position );
	return Funccode2Name( funccode, ptr, bufsize );
}

/*!	@brief 機能番号に対応する機能名称を返す．

	@param funccode [in] 機能番号
	@param ptr [out] 文字列を格納するバッファの先頭
	@param bufsize [in] 文字列を格納するバッファのサイズ

	@retval true 指定された機能番号は定義されている
	@retval false 指定された機能番号は未定義

	@date 2007.11.02 ryoji 未登録マクロも文字列を格納．戻り値の意味を変更（文字列は必ず格納）．
*/
bool CFuncLookup::Funccode2Name( int funccode, WCHAR* ptr, int bufsize ) const
{
	LPCWSTR pszStr = nullptr;

	assert( ptr != nullptr );
	assert( bufsize >= 1 );

	if( F_USERMACRO_0 <= funccode && funccode < F_USERMACRO_0 + MAX_CUSTMACRO ){
		int position = funccode - F_USERMACRO_0;
		if( m_pMacroRec[position].IsEnabled() ){
			const WCHAR *p = m_pMacroRec[position].GetTitle();
			wcsncpy_s( ptr, bufsize, p, _TRUNCATE );
		}else{
			_snwprintf_s( ptr, bufsize, _TRUNCATE, LS(STR_ERR_DLGFUNCLKUP03), position );
		}
		return true;
	}
	else if( funccode == F_MENU_RBUTTON ){
		Custmenu2Name( 0, ptr, bufsize );
		ptr[bufsize-1] = LTEXT('\0');
		return true;
	}
	else if( F_CUSTMENU_1 <= funccode && funccode < F_CUSTMENU_BASE + MAX_CUSTOM_MENU ){	// MAX_CUSTMACRO->MAX_CUSTOM_MENU	2010/3/14 Uchi
		Custmenu2Name( funccode - F_CUSTMENU_BASE, ptr, bufsize );
		ptr[bufsize-1] = LTEXT('\0');
		return true;
	}
	else if( F_MENU_FIRST <= funccode && funccode < F_MENU_NOT_USED_FIRST ){
		if( ( pszStr = LS( funccode ) )[0] != L'\0' ){
			wcsncpy( ptr, pszStr, bufsize );
			ptr[bufsize-1] = LTEXT('\0');
			return true;	// 定義されたコマンド
		}
	}
	else if( F_PLUGCOMMAND_FIRST <= funccode && funccode < F_PLUGCOMMAND_LAST ){
		if( CJackManager::getInstance()->GetCommandName( funccode, ptr, bufsize ) > 0 ){
			return true;	// プラグインコマンド
		}
	}

	// 未定義コマンド(または現在のプロセスではロードされていないプラグインなど)
	if( ( pszStr = LS( funccode ) )[0] != L'\0' ){
		wcsncpy( ptr, pszStr, bufsize );
		ptr[bufsize-1] = LTEXT('\0');
		return false;
	}

	// なにかコピーしないとループ処理などで一つ前の名前になることがあるので(-- 不明 --)をコピーしておく
	if( ( pszStr = LS( F_DISABLE ) )[0] != L'\0' ){
		wcsncpy( ptr, pszStr, bufsize );
		ptr[bufsize-1] = LTEXT('\0');
		return false;
	}
	// リソース全死亡ガード
	wcsncpy( ptr, L"unknown", bufsize );
	ptr[bufsize-1] = LTEXT('\0');

	return false;
}

/*!	@brief 機能分類番号に対応する機能名称を返す．

	@param category [in] 機能分類番号
	
	@return NULL 分類名称．取得に失敗したらNULL．
*/
const WCHAR* CFuncLookup::Category2Name( int category ) const
{
	if( category < 0 )
		return nullptr;

	if( category < nsFuncCode::nFuncKindNum ){
		return LS( nsFuncCode::ppszFuncKind[category] );
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_MACRO ){
		return LS( STR_ERR_DLGFUNCLKUP01 );
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_CUSTMENU ){
		return LS( STR_ERR_DLGFUNCLKUP02 );
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_PLUGIN ){
		return LS( STR_ERR_DLGFUNCLKUP19 );
	}
	return nullptr;
}

/*!	@brief ComboBoxに利用可能な機能分類一覧を登録する

	@param hComboBox [in(out)] データを設定するコンボボックス
*/
void CFuncLookup::SetCategory2Combo( HWND hComboBox ) const
{
	int i;

	//	コンボボックスを初期化する
	ApiWrap::Combo_ResetContent( hComboBox );

	//	固定機能リスト
	for( i = 0; i < nsFuncCode::nFuncKindNum; ++i ){
		ApiWrap::Combo_AddString( hComboBox, LS( nsFuncCode::ppszFuncKind[i] ) );
	}

	//	ユーザーマクロ
	ApiWrap::Combo_AddString( hComboBox, LS( STR_ERR_DLGFUNCLKUP01 ) );
	//	カスタムメニュー
	ApiWrap::	Combo_AddString( hComboBox, LS( STR_ERR_DLGFUNCLKUP02 ) );
	//	プラグイン
	ApiWrap::Combo_AddString( hComboBox, LS( STR_ERR_DLGFUNCLKUP19 ) );
}

/*!	@brief 指定された分類に属する機能リストをListBoxに登録する．
	
	@param hListBox [in(out)] 値を設定するリストボックス
	@param category [in] 機能分類番号

	@date 2007.11.02 ryoji 未定義コマンドは除外．処理も簡素化．
*/
void CFuncLookup::SetListItem( HWND hListBox, int category ) const
{
	WCHAR pszLabel[256];
	int n;
	int i;

	//	リストを初期化する
	ApiWrap::List_ResetContent( hListBox );

	n = GetItemCount( category );
	for( i = 0; i < n; i++ ){
		if( Pos2FuncCode( category, i ) == F_DISABLE )
			continue;
		Pos2FuncName( category, i, pszLabel, _countof(pszLabel) );
		ApiWrap::List_AddString( hListBox, pszLabel );
	}
}

/*!
	指定分類中の機能数を取得する．
	
	@param category [in] 機能分類番号
*/
int CFuncLookup::GetItemCount(int category) const
{
	if( category < 0 )
		return 0;

	if( category < nsFuncCode::nFuncKindNum ){
		return nsFuncCode::pnFuncListNumArr[category];
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_MACRO ){
		//	マクロ
		return MAX_CUSTMACRO;
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_CUSTMENU ){
		//	カスタムメニュー
		return MAX_CUSTOM_MENU;
	}
	else if( category == nsFuncCode::nFuncKindNum + LUOFFSET_PLUGIN ){
		//	プラグインコマンド
		return CJackManager::getInstance()->GetCommandCount();
	}
	return 0;
}

/*!	@brief 番号に対応するカスタムメニュー名称を返す．

	@param index [in] カスタムメニュー番号
	
	@return NULL 分類名称．取得に失敗したらNULL．
*/
const WCHAR* CFuncLookup::Custmenu2Name( int index, WCHAR buf[], int bufSize ) const
{
	if( index < 0 || CUSTMENU_INDEX_FOR_TABWND < index )
		return nullptr;

	// 共通設定で名称を設定していればそれを返す
	if ( m_pCommon->m_sCustomMenu.m_szCustMenuNameArr[ index ][0] != '\0' ) {
		wcscpyn( buf, m_pCommon->m_sCustomMenu.m_szCustMenuNameArr[ index ], bufSize );
		return m_pCommon->m_sCustomMenu.m_szCustMenuNameArr[ index ];
	}

	// 共通設定で未設定の場合、リソースのデフォルト名を返す
	if( index == 0 ){
		wcscpyn( buf, LS( STR_CUSTMENU_RIGHT_CLICK ), bufSize );
		return buf;
	}
	else if( index == CUSTMENU_INDEX_FOR_TABWND ){
		wcscpyn( buf, LS( STR_CUSTMENU_TAB ), bufSize );
		return buf;
	}
	else {
		_swprintf( buf, LS( STR_CUSTMENU_CUSTOM ), index );
		return buf;
	}

	return nullptr;
}
